package com.example.network.service.impl;

import com.example.network.Util.TokenUtils;
import com.example.network.controller.dto.EmailDTO;
import com.example.network.controller.dto.LoginDTO;
import com.example.network.controller.request.LoginRequest;
import com.example.network.controller.request.PassRequest;
import com.example.network.controller.request.UserDataRequest;
import com.example.network.controller.request.UserRequest;
import com.example.network.exception.ServiceException;
import com.example.network.mapper.UserMapper;
import com.example.network.model.entity.User;
import com.example.network.model.entity.UserData;
import com.example.network.service.UserService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

/**
 * @author LR
 */
@Slf4j
@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    private UserMapper userMapper;

    /**
     * 新增数据
     */
    @SneakyThrows
    @Override
    public Boolean insert(User user) {
        List<UserRequest> requests = userMapper.selectByEmail(user.getEmail());
        if (!requests.isEmpty()){
            throw new ServiceException("该邮箱已注册，请直接登录");
        }
        if (user.getPassword().length()<6 || user.getPassword().length()>15){
            throw new ServiceException("请输入6到15位密码");
        }
        EmailDTO emailDTO = userMapper.selectEmailCode(user.getEmail());
        if (user.getCode().equals("")){
            throw new ServiceException("请输入验证码");
        }
        if (emailDTO.getTime()<System.currentTimeMillis()){
            throw new ServiceException("验证码已过期，请重新获取");
        }
        if (!emailDTO.getVerificationCode().equals(user.getCode())){
            throw new ServiceException("验证码错误，请重新输入");
        }
        user.setPassword(encryptPassword(user.getPassword()));
//        log.info(user.getPassword());
        userMapper.insert(user);
        userMapper.insertUserData(user.getEmail(),user.getUsername());
        return true;
    }

    /**
     * 修改数据
     */
    @SneakyThrows
    @Override
    public Boolean updateByUsername(PassRequest request) {
        EmailDTO emailDTO = userMapper.selectEmailCode(request.getEmail());
        if (request.getCode().equals("")){
            throw new ServiceException("请输入验证码");
        }
        if (emailDTO.getTime()<System.currentTimeMillis()){
            throw new ServiceException("验证码已过期，请重新获取");
        }
        if (!emailDTO.getVerificationCode().equals(request.getCode())){
            throw new ServiceException("验证码错误，请重新输入");
        }
        request.setNewPass(encryptPassword(request.getNewPass()));
        Boolean flag = userMapper.updateByUsername(request);
        if (!flag) {
            throw new ServiceException("修改失败");
        }
        return true;
    }

    /**
     * 通过删除数据
     */
    @Override
    public Boolean DeleteByUserEmail(String email) {
        return userMapper.DeleteByUserEmail(email);
    }

    /**
     * 用户登录
     * @param request
     * @return
     */
    @SneakyThrows
    @Override
    public LoginDTO login(LoginRequest request) {
        UserRequest user = userMapper.getByUserEmail(request.getEmail());
        if (user == null){
            throw new ServiceException("邮箱用户未注册");
        }
        boolean flag = BCrypt.checkpw(request.getPassword(),user.getPassword());
        if (!flag){
            throw new ServiceException("密码错误，请重新输入！");
        }
        LoginDTO loginDTO = new LoginDTO();
        BeanUtils.copyProperties(user, loginDTO);
        // 生成token
        String token = TokenUtils.genToken(request.getEmail(),request.getPassword());
        loginDTO.setUserID(user.getEmail());
        loginDTO.setToken(token);
        return loginDTO;
    }

    // 使用哈希加盐进行加密
    public static String encryptPassword(String password) {
        // 生成盐并哈希密码
        return BCrypt.hashpw(password, BCrypt.gensalt(12));
    }

    /**
     * 通过id查询数据
     */
    @Override
    public User getByEmail(String email){
        return userMapper.getByEmail(email);
    }

    /**
     * 修改用户资料
     *
     * @param userData
     */
    @SneakyThrows
    @Override
    public void modifyData(UserDataRequest userData) {
        userMapper.modifyData(userData);
    }

    /**
     * 向服务器的文件系统上传用户头像
     *      因为mysql数据库不能上传大于1mb的东西，只能出此下策
     *          头像文件一般较小，所以使用write方法直接写入
     * @param file
     * @param email
     */
    @SneakyThrows
    @Override
    public void setAvatars(MultipartFile file, String email) {
        try {
            // 获取文件的字节内容
            byte[] bytes = file.getBytes();

            // 定义文件保存的路径，这里简单地将头像文件保存，并以原始文件名保存
            Path path = Paths.get("/vdb1/www/NetWorkDisk/com/UserAvatars/" + email);
            if (!Files.exists(path)){
                Files.createDirectories(path);
            }
            Path path1 = path.resolve(file.getOriginalFilename());
            // 将文件字节写入到指定的路径
            Files.write(path1, bytes);
            // 将头像信息保存到数据库
            userMapper.setAvatarsPath(String.valueOf(path1), email);
        } catch (IOException e) {
            throw new ServiceException("头像上传失败");
        }
    }

    // 查看用户资料
    @Override
    public UserData getUserData(String email) {
        return userMapper.getUserData(email);
    }

    @Override
    public ResponseEntity<InputStreamResource> getImage(String email) {
        try {
            UserData userData = userMapper.getUserData(email);
            String imagePath = userData.getAvatarsPath();
            FileInputStream inputStream = new FileInputStream(imagePath);
            final InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
            return ResponseEntity.ok()
                    .contentType(MediaType.IMAGE_JPEG)
                    .body(inputStreamResource);
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.notFound().build();
        }
    }
}


